/**
 * 1
 */

function Foo() {
  for (var i = 0; i < 5; i++) {
    setTimeout(function timer() {
      console.log(i);
    }, 1000);
  }
  console.log("sync", i);
}
Foo();

// 同步代码console.log(i)先执行，此时i是遍历后的5
// 由于setTimeout里的callback是异步执行，回调中的i都是5
// 异步回调执行时，访问的i已经是执行完遍历后的i
// 那怎么让他打印出0，1，2，3，4？
// var --> let
// 因为let会使得For循环体变成一个独立作用域
// 但是一旦改成let，同步代码就访问不了i了

/**
 * 2.
 */
function Foo() {
  for (var i = 0; i < 5; i++) {
    (function (i) {
      setTimeout(function timer() {
        console.log(i);
      }, 1000);
    })(i);
  }
  console.log(i);
}
Foo();
// 还是先执行同步代码，返回5
// 然后 0，1，2，3，4
// 这里循环体内使用了一个IIFE
// 也就是立即执行函数，IIFE将当前遍历到的i缓存了起来，使得之后的异步回调执行时，访问的i所在的作用域是IIFE的

/**
 * 3.
 */

setTimeout(function () {
  console.log("BBBB");
}, 1000);
console.log("CCCC");
setTimeout(function () {
  console.log("DDDD");
}, 0);
// 先执行同步代码 CCCC
// 计时器 DDDD, BBBB

/**
 * 4.
 */
setTimeout(function () {
  console.log("BBBB");
}, 1000);
const start = new Date();
while (new Date() - start < 3000) {}
console.log("CCCC");
setTimeout(function () {
  console.log("DDDD");
}, 0);
// BBBB先放入异步队列 过了三秒后， CCCC
// CCCC BBBB DDDD